<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="aSgww" id="aSgww"><span data-lake-id="u21654781" id="u21654781">典型回答</span></h1>
  <p data-lake-id="u794bcf1a" id="u794bcf1a"><br></p>
  <p data-lake-id="u273a613b" id="u273a613b"><br></p>
  <p data-lake-id="ue56e14ed" id="ue56e14ed" style="text-align: left"><span data-lake-id="ud86e38a8" id="ud86e38a8">由于CPU和主存的处理速度上存在一定差别，为了匹配这种差距，提升计算机能力，人们在CPU和主存之间增加了多层高速缓存。</span></p>
  <p data-lake-id="uc312ec53" id="uc312ec53" style="text-align: left"><span data-lake-id="u6c7cd084" id="u6c7cd084">​</span><br></p>
  <p data-lake-id="uffaf9849" id="uffaf9849" style="text-align: left"><span data-lake-id="u48575ffd" id="u48575ffd">每个CPU会有L1、L2甚至L3缓存，在多核计算机中会有多个CPU，那么就会存在多套缓存，那么这多套缓存之间的数据就可能出现不一致的现象。为了解决这个问题，有了内存模型。内存模型定义了共享内存系统中多线程程序读写操作行为的规范。通过这些规则来规范对内存的读写操作，从而保证指令执行的正确性。</span></p>
  <p data-lake-id="u9529d5d0" id="u9529d5d0" style="text-align: left"><br></p>
  <p data-lake-id="u1850be90" id="u1850be90" style="text-align: left"><span data-lake-id="uce1b6178" id="uce1b6178">但是引入了多级缓存之后，就会带来一个缓存一致性的问题。</span></p>
  <p data-lake-id="u146979ba" id="u146979ba"><span data-lake-id="u035ba22c" id="u035ba22c">​</span><br></p>
  <p data-lake-id="uec17722e" id="uec17722e"><span data-lake-id="u55d10472" id="u55d10472">首先，缓存一致性是由于引入缓存而导致的问题，所以，这是很多CPU厂商必须解决的问题。为了解决前面提到的缓存数据不一致的问题，人们提出过很多方案，通常来说有以下2种方案：</span></p>
  <p data-lake-id="u8723757f" id="u8723757f"><span data-lake-id="ua9f758b1" id="ua9f758b1">1、通过在总线加</span><span data-lake-id="ueffcda84" id="ueffcda84">LOCK#</span><span data-lake-id="ud9250fe0" id="ud9250fe0">锁的方式。</span></p>
  <p data-lake-id="u2147397f" id="u2147397f"><span data-lake-id="ub49c57e6" id="ub49c57e6">2、通过缓存一致性协议（Cache Coherence Protocol）。</span></p>
  <p data-lake-id="u1ded8400" id="u1ded8400"><span data-lake-id="ufe65b4e3" id="ufe65b4e3">​</span><br></p>
  <p data-lake-id="ub54d6117" id="ub54d6117"><span data-lake-id="udea0fd4f" id="udea0fd4f">在早期的CPU当中，是通过在总线上加</span><span data-lake-id="u0485001b" id="u0485001b">LOCK#</span><span data-lake-id="ucb15f885" id="ucb15f885">锁的形式来解决缓存不一致的问题。因为CPU和其他部件进行通信都是通过总线来进行的，如果对总线加</span><span data-lake-id="u3ff1f268" id="u3ff1f268">LOCK#</span><span data-lake-id="u24c71252" id="u24c71252">锁的话，也就是说阻塞了其他CPU对其他部件访问（如内存），从而使得只能有一个CPU能使用这个变量的内存。在总线上发出了</span><span data-lake-id="u84ad92f8" id="u84ad92f8">LCOK#</span><span data-lake-id="ue29c4370" id="ue29c4370">锁的信号，那么只有等待这段代码完全执行完毕之后，其他CPU才能从其内存读取变量，然后进行相应的操作。这样就解决了缓存不一致的问题。</span></p>
  <p data-lake-id="ub40220f9" id="ub40220f9"><span data-lake-id="ub2e9289c" id="ub2e9289c">​</span><br></p>
  <p data-lake-id="u52fab33c" id="u52fab33c"><span data-lake-id="u1caa1767" id="u1caa1767">但是由于在锁住总线期间，其他CPU无法访问内存，会导致效率低下。因此出现了第二种解决方案，通过缓存一致性协议来解决缓存一致性问题。</span></p>
  <h3 data-lake-id="gIgzI" id="gIgzI" style="text-align: left"><span data-lake-id="ud5966dad" id="ud5966dad" style="color: rgb(29, 35, 39)">缓存一致性协议</span></h3>
  <p data-lake-id="u0b2f6d8e" id="u0b2f6d8e"><span data-lake-id="u631e6fca" id="u631e6fca">缓存一致性协议（Cache Coherence Protocol），最出名的就是Intel 的MESI协议，MESI协议保证了每个缓存中使用的共享变量的副本是一致的。</span></p>
  <p data-lake-id="u6bfee188" id="u6bfee188"><span data-lake-id="u6151ef46" id="u6151ef46">​</span><br></p>
  <p data-lake-id="uc0943222" id="uc0943222"><span data-lake-id="ue58b965c" id="ue58b965c">MESI的核心的思想是：当CPU写数据时，如果发现操作的变量是共享变量，即在其他CPU中也存在该变量的副本，会发出信号通知其他CPU将该变量的缓存行置为无效状态，因此当其他CPU需要读取这个变量时，发现自己缓存中缓存该变量的缓存行是无效的，那么它就会从内存重新读取。</span></p>
  <p data-lake-id="u25324216" id="u25324216"><span data-lake-id="u185b7470" id="u185b7470">​</span><br></p>
  <p data-lake-id="u24378482" id="u24378482"><span data-lake-id="ue6962cbe" id="ue6962cbe">在MESI协议中，每个缓存可能有有4个状态，它们分别是：</span></p>
  <p data-lake-id="uab9531f3" id="uab9531f3"><span data-lake-id="u4fc1687e" id="u4fc1687e">​</span><br></p>
  <p data-lake-id="u7527d9ed" id="u7527d9ed"><span data-lake-id="u749583dc" id="u749583dc">M(Modified)</span><span data-lake-id="u978d4b2b" id="u978d4b2b">：这行数据有效，数据被修改了，和内存中的数据不一致，数据只存在于本Cache中。</span></p>
  <p data-lake-id="u8430d7ba" id="u8430d7ba"><span data-lake-id="ub07fe1df" id="ub07fe1df">E(Exclusive)</span><span data-lake-id="ube7d2567" id="ube7d2567">：这行数据有效，数据和内存中的数据一致，数据只存在于本Cache中。</span></p>
  <p data-lake-id="udaad7ad9" id="udaad7ad9"><span data-lake-id="u077c83f7" id="u077c83f7">S(Shared)</span><span data-lake-id="u2bdeaa63" id="u2bdeaa63">：这行数据有效，数据和内存中的数据一致，数据存在于很多Cache中。</span></p>
  <p data-lake-id="u3c3a32f4" id="u3c3a32f4"><span data-lake-id="ub4caa6cb" id="ub4caa6cb">I(Invalid)</span><span data-lake-id="ub94ef99a" id="ub94ef99a">：这行数据无效。</span></p>
  <p data-lake-id="ucee0885b" id="ucee0885b"><span data-lake-id="u943e6710" id="u943e6710">​</span><br></p>
  <p data-lake-id="u235a9505" id="u235a9505"><span data-lake-id="u76286b4f" id="u76286b4f">有了这四种状态之后，MESI协议的工作流程如下：</span></p>
  <ol list="uda5bcefe">
   <li fid="u8daf80da" data-lake-id="u2e7799d4" id="u2e7799d4" data-lake-index-type="true"><span data-lake-id="ufc5cff20" id="ufc5cff20">当一个处理器需要读取一个缓存行时，它会首先检查该缓存行的状态。</span></li>
   <li fid="u8daf80da" data-lake-id="uf7810d27" id="uf7810d27" data-lake-index-type="true"><span data-lake-id="uad35ca48" id="uad35ca48">如果状态是Exclusive或Shared，则直接从缓存中读取数据。因为这两种状态中数据都是有效的。</span></li>
   <li fid="u8daf80da" data-lake-id="u636aeb55" id="u636aeb55" data-lake-index-type="true"><span data-lake-id="u137c98fc" id="u137c98fc">如果状态是Modified，则表明数据被修改了，则需要先将修改的数据写回主内存，然后再从主内存中读取数据。</span></li>
   <li fid="u8daf80da" data-lake-id="u8cca6251" id="u8cca6251" data-lake-index-type="true"><span data-lake-id="u056e6ebd" id="u056e6ebd">如果状态是Invalid，则需要从主内存中加载数据到缓存，并设置状态为Exclusive或Shared。</span></li>
  </ol>
  <p data-lake-id="u41fc143b" id="u41fc143b"><br></p>
  <p data-lake-id="ua6476f30" id="ua6476f30"><span data-lake-id="u8afdba67" id="u8afdba67">当一个处理器修改了一个缓存行时，它会将状态设置为Modified，并通知其他处理器或核心该缓存行的状态已被修改，从而导致其他处理器中相应缓存行的状态变为Invalid。</span></p>
  <p data-lake-id="u008aed0c" id="u008aed0c"><span data-lake-id="u5d7b0738" id="u5d7b0738">​</span><br></p>
  <p data-lake-id="ue39ef506" id="ue39ef506"><span data-lake-id="u12234450" id="u12234450">通过这种方式，MESI协议确保了多个缓存中的数据一致性，避免了数据不一致导致的错误。它是一种常见的缓存一致性协议，被广泛应用于多核处理器和多处理器系统中。</span></p>
 </body>
</html>